/*
 * @(#)PagerInfo.java $version 2010. 8. 11
 *
 * Copyright 2007-2010 NHN Corp. All rights Reserved. 
 * NHN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.nhncorp.usf.core.result.template.directive;

import java.io.UnsupportedEncodingException;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.nhncorp.lucy.common.config.model.ApplicationInfo;

import com.nhncorp.usf.core.config.PagerConfigInfo;
import com.nhncorp.usf.core.config.PagerConfigInfos;
import com.nhncorp.usf.core.util.StringUtil;

/**
 * Page 네비게이션 정보를 포함하기 위한 모델
 * <p/>
 * 웹환경에서는 {@link PagerInfoInterceptor}에 의해서 초기화 된다.
 * 
 * @author Web Platform Development Team
 * @see PagerInfoInterceptor
 */
public class PagerInfo {
	public static final String ISO8859_1 = "ISO-8859-1";

	/**
	 * 환경 설정에 정의된 PageNavigator의 타입 기본 값은 "default"이다.
	 */
	private String type = "default";

	/**
	 * 전체 데이터 수.
	 */
	private Integer totalRows = -1;

	/**
	 * 한 페이지에 보여질 데이터 수.
	 */
	private Integer pageSize = 0;

	/**
	 * 페이지 이동을 위한 색인 수.
	 */
	private Integer indexSize = 0;

	/**
	 * 현재 페이지 번호.
	 */
	private Integer page = 1;

	/**
	 * {@link HttpServletRequest#getRequestURI()}
	 */
	private String requestURI;

	/**
	 * {@link HttpServletRequest#getMethod()}
	 */
	private String requestMethod;

	/**
	 * {@link HttpServletRequest#getQueryString()}
	 */
	private String queryString;

	static Log log = LogFactory.getLog(PagerInfo.class);

	/**
	 * 생성자
	 * 
	 * @param page           현재 페이지 번호
	 * @param requestURI     요청 URI
	 * @param queryString    요청 QueryString
	 * @param requestMethod  요청방법( POST, GET)
	 */
	public PagerInfo(int page, String requestURI, String queryString,
			String requestMethod) {
		this.page = page;
		this.requestURI = requestURI;
		this.requestMethod = requestMethod;
		setQueryString(queryString);
	}

	// -- init ----------------------------------------------------------------

	/**
	 * PagerInfo 초기화한다.
	 * 
	 * @param type      PagerNavigator 타입
	 * @param totalRows 전체 데이터 수
	 * @param pageSize  한페이지에 보일 데이터수
	 * @param indexSize 페이지 이동을 위한 색인 수
	 */
	public void init(String type, Integer totalRows, Integer pageSize,
			Integer indexSize) {
		if (type != null && type.trim().length() != 0) {
			this.type = type;
		}

		PagerConfigInfo config = PagerConfigInfos.get(type);
		this.totalRows = totalRows;
		this.indexSize = indexSize == null ? (config == null ? 0 : config.getIndexSize()) : indexSize;
		this.pageSize = pageSize == null ? (config == null ? 0 : config.getPageSize()) : pageSize;

		if (this.page > getLastPage()) {
			this.page = getLastPage();
		}
	}

	/**
	 * 전체 데이터 수를 반환한다.
	 * 
	 * @return int
	 */
	public int getTotalRows() {
		return totalRows;
	}

	/**
	 * 페이지 이동을 위한 색인 수를 반환한다.
	 * 
	 * @return int
	 */
	public int getIndexSize() {
		return indexSize;
	}

	/**
	 * 한 페이지에 보일 데이터 수를 반환한다.
	 * 
	 * @return int
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * PageNavigator 타입을 반환한다.
	 * 
	 * @return String
	 */
	public String getType() {
		return type;
	}

	/**
	 * 현재 페이지에 대한 시작 색인 값을 반환한다.
	 * 
	 * @return int
	 */
	public int getStartRownum() {
		return pageSize * (page - 1) + 1;
	}

	/**
	 * 현재 페이지에 대한 마지막 색인 값을 반환한다.
	 * 
	 * @return int
	 */
	public int getEndRownum() {
		return Math.min(pageSize * page, totalRows);
	}

	/**
	 * 현재 페이지를 반환한다.
	 * 
	 * @return int
	 */
	public int getPage() {
		if (page > getLastPage()) {
			return getLastPage();
		}

		return page;
	}

	/**
	 * 전체 페이지 수를 반환한다.
	 * 
	 * @return int
	 */
	public int getTotalPages() {
		if (pageSize == 0) {
			throw new IllegalStateException("pageSize is Zero.");
		}

		return (totalRows - 1) / pageSize + 1;
	}

	/**
	 * 첫 페이지 색인을 반환한다.
	 * 
	 * @return int
	 */
	public int getFirstPage() {
		//		if (indexSize == 0) {
		//			throw new IllegalStateException("indexSize is Zero.");
		//		}

		return ((page - 1) / indexSize) * indexSize + 1;
	}

	/**
	 * 마지막 페이지 색인을 반환한다.
	 * 
	 * @return int
	 */
	public int getLastPage() {
		return Math.min(getFirstPage() + indexSize - 1, getTotalPages());
	}

	/**
	 * 요청 QueryString을 반환한다.
	 * 
	 * @return String
	 */
	public String getQueryString() {
		return queryString;
	}

	/**
	 * 요청 QueryString을 설정한다. Get 방식으로 전달된 경우 환경설정 정보(
	 * {@link ApplicationInfo#getPageEncoding()})를 이용해서 인코딩을 적용한다.
	 * 
	 * @param queryString
	 *            String
	 */
	public void setQueryString(String queryString) {
		String lQueryString = queryString;

		if (StringUtil.isNotEmpty(lQueryString, false)
				&& StringUtil.isNotEmpty(requestMethod, false)) {
			if (requestMethod.equalsIgnoreCase("GET")) {
				String encoding = ApplicationInfo.getPageEncoding();
				try {
					if (!ISO8859_1.equals(encoding)) {
						lQueryString = new String(lQueryString.getBytes(ISO8859_1), encoding);
					}
				} catch (UnsupportedEncodingException except) {
					log.debug("fail to encoding(" + encoding + ") : "
							+ lQueryString);

					// ignore ? -> 오류 발생시 인코딩 안함.
				}
			}
		}

		this.queryString = lQueryString;
	}

	/**
	 * 요청 QueryString을 반환한다.
	 * 
	 * @return String
	 */
	public String getRequestURI() {
		return requestURI;
	}

	/**
	 * 요청 방법(POST, GET)을 반환한다.
	 * 
	 * @return String
	 */
	public String getRequestMethod() {
		return requestMethod;
	}

	// -- static util ---------------------------------------------------------

	/**
	 * {@link HttpServletRequest}에 저장된 {@link PagerInfo} 객체를 반환한다.
	 * 
	 * @param request HttpServletRequest
	 * @return PagerInfo
	 */
	public static PagerInfo getPagerInfo(HttpServletRequest request) {
		return (PagerInfo) request.getAttribute("pagerInfo");
	}

}